package com.kwdb.importtool.util;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

/**
 * 日志工具类
 * 提供统一的日志记录和配置管理
 */
@Slf4j
public class LoggerUtil {

    // 日志级别
    public enum LogLevel {
        TRACE, DEBUG, INFO, WARN, ERROR
    }

    // 默认配置
    private static final String DEFAULT_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
    private static final String DEFAULT_LOG_FILE_NAME = "migration-tool.log";
    private static final String DEFAULT_LOG_DIR = "logs";
    private static final int DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
    private static final int DEFAULT_MAX_HISTORY = 30; // 保留30天

    // 日志配置文件路径
    private static final String[] CONFIG_FILE_PATHS = {
            "config/log4j2.xml",
            "log4j2.xml",
            "config/logging.properties",
            "logging.properties"
    };

    private LoggerUtil() {
        // 工具类，防止实例化
    }

    /**
     * 初始化日志系统（兼容旧版本）
     */
    public static void initializeLogging() {
        initializeLogging(null, null);
    }

    /**
     * 初始化日志系统（兼容旧版本）
     */
    public static void initializeLogging(String configFilePath) {
        initializeLogging(configFilePath, null);
    }

    /**
     * 初始化日志系统（新增支持outputDir参数）
     */
    public static void initializeLogging(String configFilePath, String outputDir) {
        try {
            // 设置日志输出目录（优先使用传入的outputDir，否则使用默认值）
            String effectiveOutputDir = (outputDir != null && !outputDir.trim().isEmpty()) ?
                    outputDir : DEFAULT_LOG_DIR;

            // 设置系统属性，供log4j2.xml使用
            System.setProperty("LOG_HOME", effectiveOutputDir);

            // 查找配置文件
            File configFile = findLogConfigFile(configFilePath);

            if (configFile != null && configFile.exists()) {
                // 使用配置文件
                setupWithConfigFile(configFile);
                log.info("The logging system is initialized with a configuration file: {}", configFile.getAbsolutePath());
            } else {
                // 使用默认配置
                setupDefaultLogging(effectiveOutputDir);
                log.info("The logging system is initialized with the default configuration");
            }

            // 注册关闭钩子
            registerShutdownHook();

        } catch (Exception e) {
            System.err.println("Log system initialization failed: " + e.getMessage());
            setupFallbackLogging();
        }
    }

    /**
     * 查找日志配置文件
     */
    private static File findLogConfigFile(String specifiedPath) {
        // 如果指定了配置文件路径，优先使用
        if (specifiedPath != null && !specifiedPath.trim().isEmpty()) {
            File configFile = new File(specifiedPath);
            if (configFile.exists()) {
                return configFile;
            }
        }

        // 在预定义路径中查找
        for (String path : CONFIG_FILE_PATHS) {
            File configFile = new File(path);
            if (configFile.exists()) {
                return configFile;
            }

            // 也在类路径中查找
            if (LoggerUtil.class.getClassLoader().getResource(path) != null) {
                return new File(path);
            }
        }

        return null;
    }

    /**
     * 使用配置文件设置日志
     */
    private static void setupWithConfigFile(File configFile) {
        String fileName = configFile.getName().toLowerCase();

        if (fileName.endsWith(".xml")) {
            setupLog4j2WithConfigFile(configFile);
        } else if (fileName.endsWith(".properties")) {
            setupLoggingProperties(configFile);
        } else {
            log.warn("Unsupported log profile formats: {}, Use the default configuration", fileName);
            setupDefaultLogging();
        }
    }

    /**
     * 设置Log4j2配置文件
     */
    private static void setupLog4j2WithConfigFile(File configFile) {
        try {
            System.setProperty("log4j.configurationFile", configFile.getAbsolutePath());
            log.info("Log4j2 configuration file loaded: {}", configFile.getAbsolutePath());
        } catch (Exception e) {
            log.error("Failed to load Log4j2 configuration file", e);
            setupDefaultLogging();
        }
    }

    /**
     * 设置日志属性文件
     */
    private static void setupLoggingProperties(File configFile) {
        try (InputStream is = new FileInputStream(configFile)) {
            Properties props = new Properties();
            props.load(is);

            log.info("theLogAttributeFileIsLoaded: {}", configFile.getAbsolutePath());
        } catch (IOException e) {
            log.error("failedToLoadLogAttributeFiles", e);
            setupDefaultLogging();
        }
    }

    /**
     * 设置默认日志配置（新增支持outputDir参数）
     */
    private static void setupDefaultLogging(String outputDir) {
        try {
            // 创建日志目录
            File logDir = new File(outputDir);
            if (!logDir.exists()) {
                if (!logDir.mkdirs()) {
                    System.err.println("Unable to create log directory: " + logDir.getAbsolutePath());
                }
            }

            // 设置系统属性（如果使用Log4j2）
            System.setProperty("log4j2.configuration", "default");

        } catch (Exception e) {
            System.err.println("Failed to set default log configuration: " + e.getMessage());
        }
    }

    /**
     * 设置默认日志配置（兼容内部调用）
     */
    private static void setupDefaultLogging() {
        setupDefaultLogging(DEFAULT_LOG_DIR);
    }

    /**
     * 设置备用日志配置（当所有配置都失败时使用）
     */
    public static void setupFallbackLogging() {
        // 使用最简单的控制台日志
        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
        System.setProperty("org.slf4j.simpleLogger.showDateTime", "true");
        System.setProperty("org.slf4j.simpleLogger.dateTimeFormat", "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 注册关闭钩子
     */
    private static void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("theAppIsClosing...");
            try {
                // 等待日志刷新
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }));
    }

    /**
     * 获取当前日志文件路径
     */
    public static String getCurrentLogFilePath() {
        String logHome = System.getProperty("LOG_HOME", DEFAULT_LOG_DIR);
        return logHome + File.separator + DEFAULT_LOG_FILE_NAME;
    }

    /**
     * 获取日志文件列表
     */
    public static File[] getLogFiles() {
        String logHome = System.getProperty("LOG_HOME", DEFAULT_LOG_DIR);
        File logDir = new File(logHome);
        if (logDir.exists() && logDir.isDirectory()) {
            return logDir.listFiles((dir, name) ->
                    name.toLowerCase().endsWith(".log") || name.toLowerCase().endsWith(".txt"));
        }
        return new File[0];
    }

    /**
     * 清理旧日志文件
     */
    public static void cleanupOldLogs(int keepDays) {
        String logHome = System.getProperty("LOG_HOME", DEFAULT_LOG_DIR);
        File logDir = new File(logHome);
        if (!logDir.exists() || !logDir.isDirectory()) {
            return;
        }

        File[] logFiles = getLogFiles();
        long cutoffTime = System.currentTimeMillis() - (keepDays * 24L * 60 * 60 * 1000);
        int deletedCount = 0;

        for (File logFile : logFiles) {
            if (logFile.lastModified() < cutoffTime) {
                if (logFile.delete()) {
                    deletedCount++;
                    log.debug("deleteOldLogFiles: {}", logFile.getName());
                } else {
                    log.warn("oldLogFilesCannotBeDeleted: {}", logFile.getName());
                }
            }
        }

        if (deletedCount > 0) {
            log.info("清理了 {} 个旧日志文件", deletedCount);
        }
    }

    /* 以下是原有日志方法的保留（未修改部分） */

    public static Logger getLogger(Class<?> clazz) {
        return LoggerFactory.getLogger(clazz);
    }

    public static Logger getLogger(String name) {
        return LoggerFactory.getLogger(name);
    }

    public static void trace(String message) {
        log.trace(message);
    }

    public static void trace(String format, Object... args) {
        log.trace(format, args);
    }

    public static void trace(String message, Throwable throwable) {
        log.trace(message, throwable);
    }

    public static void debug(String message) {
        log.debug(message);
    }

    public static void debug(String format, Object... args) {
        log.debug(format, args);
    }

    public static void debug(String message, Throwable throwable) {
        log.debug(message, throwable);
    }

    public static void info(String message) {
        log.info(message);
    }

    public static void info(String format, Object... args) {
        log.info(format, args);
    }

    public static void info(String message, Throwable throwable) {
        log.info(message, throwable);
    }

    public static void warn(String message) {
        log.warn(message);
    }

    public static void warn(String format, Object... args) {
        log.warn(format, args);
    }

    public static void warn(String message, Throwable throwable) {
        log.warn(message, throwable);
    }

    public static void error(String message) {
        log.error(message);
    }

    public static void error(String format, Object... args) {
        log.error(format, args);
    }

    public static void error(String message, Throwable throwable) {
        log.error(message, throwable);
    }

    public static void enter(String methodName) {
        if (log.isDebugEnabled()) {
            log.debug("→ entryMethod: {}", methodName);
        }
    }

    public static void enter(String className, String methodName) {
        if (log.isDebugEnabled()) {
            log.debug("→ entryMethod: {}.{}", className, methodName);
        }
    }

    public static void exit(String methodName) {
        if (log.isDebugEnabled()) {
            log.debug("← exitMethod: {}", methodName);
        }
    }

    public static void exit(String className, String methodName) {
        if (log.isDebugEnabled()) {
            log.debug("← exitMethod: {}.{}", className, methodName);
        }
    }

    public static void exit(String methodName, Object result) {
        if (log.isDebugEnabled()) {
            log.debug("← exitMethod: {}, returnValue: {}", methodName, result);
        }
    }

    public static void performance(String operation, long startTime, long endTime) {
        long duration = endTime - startTime;
        if (duration > 1000) {
            log.warn("performanceWarning - {} take: {} ms", operation, duration);
        } else if (log.isInfoEnabled()) {
            log.info("performanceStatistics - {} take: {} ms", operation, duration);
        }
    }

    public static void dbOperation(String operation, String sql, long duration) {
        if (duration > 5000) {
            log.error("databaseOperationTimeout - {} take: {} ms, SQL: {}", operation, duration, abbreviateSQL(sql));
        } else if (duration > 1000) {
            log.warn("theDatabaseIsSlow - {} take: {} ms, SQL: {}", operation, duration, abbreviateSQL(sql));
        } else if (log.isDebugEnabled()) {
            log.debug("databaseOperations - {} take: {} ms, SQL: {}", operation, duration, abbreviateSQL(sql));
        }
    }

    private static String abbreviateSQL(String sql) {
        if (sql == null) {
            return "null";
        }
        return sql.length() <= 100 ? sql : sql.substring(0, 100) + "...";
    }

    public static void fileOperation(String operation, String filePath, long fileSize) {
        if (log.isInfoEnabled()) {
            String sizeInfo = fileSize > 0 ? FileUtils.formatFileSize(fileSize) : "theSizeIsUnknown";
            log.info("fileOperations - {}: {} ({})", operation, filePath, sizeInfo);
        }
    }

    public static void migrationProgress(String step, int progress, String details) {
        if (progress >= 100) {
            log.info("🎉 theMigrationIsComplete: {} - {}", step, details);
        } else if (progress <= 0) {
            log.info("🚀 startTheMigration: {} - {}", step, details);
        } else {
            log.info("📊 migrationProgress: {}% - {} - {}", progress, step, details);
        }
    }

    public static void errorStatistics(String operation, int total, int errors, int warnings) {
        if (errors > 0) {
            log.error("errorStatistics - {}: total={}, mistake={}, warning={}, success={:.2f}%",
                    operation, total, errors, warnings,
                    total > 0 ? (total - errors) * 100.0 / total : 0);
        } else if (warnings > 0) {
            log.warn("warningStatistics - {}: total={}, warning={}, success=100%",
                    operation, total, warnings);
        } else {
            log.info("successStatistics - {}: total={}, success=100%", operation, total);
        }
    }

    public static void showLogDialog(Component parent, String title, String message, LogLevel level) {
        SwingUtilities.invokeLater(() -> {
            int messageType = JOptionPane.PLAIN_MESSAGE;
            switch (level) {
                case ERROR:
                    messageType = JOptionPane.ERROR_MESSAGE;
                    break;
                case WARN:
                    messageType = JOptionPane.WARNING_MESSAGE;
                    break;
                case INFO:
                    messageType = JOptionPane.INFORMATION_MESSAGE;
                    break;
            }
            JOptionPane.showMessageDialog(parent, message, title, messageType);
        });
    }

    public static void showDetailedLogDialog(Component parent, String title, String summary, String details) {
        SwingUtilities.invokeLater(() -> {
            JTextArea summaryArea = new JTextArea(summary);
            summaryArea.setEditable(false);
            summaryArea.setLineWrap(true);
            summaryArea.setWrapStyleWord(true);
            summaryArea.setBackground(parent.getBackground());

            JTextArea detailsArea = new JTextArea(details);
            detailsArea.setEditable(false);
            detailsArea.setFont(new Font("Monospaced", Font.PLAIN, 11));

            JScrollPane detailsScrollPane = new JScrollPane(detailsArea);
            detailsScrollPane.setPreferredSize(new Dimension(500, 300));
            detailsScrollPane.setBorder(BorderFactory.createTitledBorder("详细信息"));

            JPanel panel = new JPanel(new BorderLayout(10, 10));
            panel.add(summaryArea, BorderLayout.NORTH);
            panel.add(detailsScrollPane, BorderLayout.CENTER);

            JOptionPane.showMessageDialog(parent, panel, title, JOptionPane.INFORMATION_MESSAGE);
        });
    }

    /**
     * 日志配置信息类
     */
    public static class LogConfig {
        private String logLevel;
        private String logFile;
        private int maxFileSize;
        private int maxHistory;
        private String pattern;

        public String getLogLevel() { return logLevel; }
        public void setLogLevel(String logLevel) { this.logLevel = logLevel; }
        public String getLogFile() { return logFile; }
        public void setLogFile(String logFile) { this.logFile = logFile; }
        public int getMaxFileSize() { return maxFileSize; }
        public void setMaxFileSize(int maxFileSize) { this.maxFileSize = maxFileSize; }
        public int getMaxHistory() { return maxHistory; }
        public void setMaxHistory(int maxHistory) { this.maxHistory = maxHistory; }
        public String getPattern() { return pattern; }
        public void setPattern(String pattern) { this.pattern = pattern; }

        @Override
        public String toString() {
            return String.format("LogConfig{level=%s, file=%s, maxSize=%d, maxHistory=%d, pattern=%s}",
                    logLevel, logFile, maxFileSize, maxHistory, pattern);
        }
    }

    public static LogConfig getCurrentLogConfig() {
        LogConfig config = new LogConfig();
        config.setLogLevel(getCurrentLogLevel().name());
        config.setLogFile(getCurrentLogFilePath());
        config.setMaxFileSize(DEFAULT_MAX_FILE_SIZE);
        config.setMaxHistory(DEFAULT_MAX_HISTORY);
        config.setPattern(DEFAULT_LOG_PATTERN);
        return config;
    }

    public static LogLevel getCurrentLogLevel() {
        if (log.isTraceEnabled()) {
            return LogLevel.TRACE;
        } else if (log.isDebugEnabled()) {
            return LogLevel.DEBUG;
        } else if (log.isInfoEnabled()) {
            return LogLevel.INFO;
        } else if (log.isWarnEnabled()) {
            return LogLevel.WARN;
        } else {
            return LogLevel.ERROR;
        }
    }

    public static String generateLogReport() {
        StringBuilder report = new StringBuilder();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        report.append("=== 应用程序日志报告 ===\n");
        report.append("生成时间: ").append(sdf.format(new Date())).append("\n");
        report.append("日志级别: ").append(getCurrentLogLevel()).append("\n");
        report.append("日志目录: ").append(System.getProperty("LOG_HOME", DEFAULT_LOG_DIR)).append("\n");
        report.append("日志文件: ").append(getCurrentLogFilePath()).append("\n");

        File[] logFiles = getLogFiles();
        report.append("日志文件数量: ").append(logFiles.length).append("\n");

        long totalSize = 0;
        for (File logFile : logFiles) {
            totalSize += logFile.length();
        }
        report.append("日志总大小: ").append(FileUtils.formatFileSize(totalSize)).append("\n");

        return report.toString();
    }
}